#include "link.h"
#include "components\polsys_lib\polsys_lib.h"


// 1: 使用延时函数同步等待（VBUS识别包输出40ms高电平）
#define _SYNC_WAIT      1



typedef enum _link_rx_step
{
    LINK_RX_HEAD_H,
    LINK_RX_HEAD_L,
    LINK_RX_IDENTIFY_ANTH_CODE,     // 8字节验证码
    LINK_RX_IDENTIFY_DATA_LEN,      // 1个字节识别包的长度
    LINK_RX_LENGTH,                 // 2个字节普通包的长度
    LINK_RX_DATA
}link_rx_step_t;

typedef enum _link_status
{
    LINK_ST_IDLE,           // 空闲
    LINK_ST_WAIT_IDENTIFY,  // 等待识别包的回应（已发送识别包）
    LINK_ST_WAIT_DATA       // 等待数据包的回应（已发送数据包）
}link_status_t;


static bool mPlugIn = false;
static u8 mRxBuff[32];
static u16 mPkgLen = 0;
static link_status_t Link_mStatus = LINK_ST_IDLE;
static u8 mWaitTime = 0;    // 等待接收数据计时，收到头H后开始计时。
static u8 mTimeOut = 0;     // 超时时间
static link_rx_step_t mRxStep = LINK_RX_HEAD_H;
static u8 mBuffIndex = 0;
// volatile static bit mRxFinish = false;
volatile static link_ev_t mEventBuff = LINK_EV_NULL;    // 中断中对事件进行缓存
static bit mPortLocked = false; // 本包数据锁定一个端口，避免其它端口干扰
static u16 mDataRced;       // 用于接收过程中记录已接收到的数据

static u8 *mTxBuff;
static u16 mTxBuffLen;
static link_port_t mLastRecPort = LINK_PORT_UNKNOW;       // 最后一次收到数据的端口
#if (!_SYNC_WAIT)
static u8 mVBusTxDelayTime = 0xff;   // VBUS通信输出高等待时间计时， VBUS发送识别包之前必须先输出高电平40ms以确保从机被唤醒。
#endif

static polsys_task_t mTimer;

// 外部函数声明

void _Link_Event(link_ev_t e);

// 内部函数声明

static void LinkLoop();
static void SendData();
static void VBusStartSend();

// 对外提供的函数

// 由外部调用（一般是UART中断）来通知 Smcp 收到了新的数据（1个字节）。
// 外部调用事件：收到了新的数据（1个字节）
void Link_EvReceivedByte(u8 dat, link_port_t port)
{
    bit available;  // 收到的字节数据是有用的

    mWaitTime = 0; // 超时清零

    if (mPortLocked)
    {
        if (mLastRecPort == port)
        {
            available = true;
        }
        else
        {
            available = false;
        }
    }
    else
    {
        available = true;
    }
    if(available)// 收到的字节数据是有用的
    {
        switch (mRxStep)
        {
        case LINK_RX_HEAD_H: //接收头H
            if (dat == 0x55)
            {
                mRxStep = LINK_RX_HEAD_L; //进入下一步
                mPortLocked = true;
                mLastRecPort = port;
                if(port == LINK_PORT_VBUS)
                {
                    mEventBuff = LINK_EV_SLOW_PORT;   // 稍后进行事件通知
                    mTimeOut = 25; // VBUS通信是慢速接口，超时时间要长
                }
                else
                {
                    mTimeOut = 10;
                }
            }
            break;
        case LINK_RX_HEAD_L: //接收头L
            if (dat == 0xAA)
            {
                if(Link_mStatus == LINK_ST_WAIT_IDENTIFY)
                {
                    mRxStep = LINK_RX_IDENTIFY_ANTH_CODE; //进入下一步
                }
                else
                {
                    mRxStep = LINK_RX_LENGTH; //进入下一步
                }
            }
            else if (dat == 0x55)
            {
                mRxStep = LINK_RX_HEAD_L; //继续这一步
            }
            else
            {
                mRxStep = LINK_RX_HEAD_H; //重新开始接收头H
                mBuffIndex = 0;
                mPortLocked = false;
            }
            break;
        case LINK_RX_IDENTIFY_ANTH_CODE: // 接收验证码
            mRxBuff[mBuffIndex++] = dat;
            if(mBuffIndex == 8)
            {
                mRxStep = LINK_RX_IDENTIFY_DATA_LEN;
            }
            break;
        case LINK_RX_IDENTIFY_DATA_LEN: // 接收识别包的数据长度，可能没有
            mRxBuff[mBuffIndex++] = dat;
            mPkgLen = dat;
            if(mPkgLen == 0)
            {
                mEventBuff = LINK_EV_RECEIVED_PKG;  //标记一包接收完毕,稍后进行事件通知
                Link_mStatus = LINK_ST_IDLE;
                mRxStep = LINK_RX_HEAD_H;      //重新开始接收头H
                mBuffIndex = 0;
                mPortLocked = false;
            }
            else 
            {
                mRxStep = LINK_RX_DATA;
                mDataRced = 0;
            }
            break;
        case LINK_RX_LENGTH: //接收2字节普通包长度
            mRxBuff[mBuffIndex++] = dat;
            if (mBuffIndex == 2)
            {
                mPkgLen = MAKE_U16(mRxBuff[0], mRxBuff[1]);
                if (mPkgLen == 0)
                {
                    mRxStep = LINK_RX_HEAD_H; //重新开始接收头H
                    mBuffIndex  = 0;
                }
                else
                {
                    mRxStep = LINK_RX_DATA;
					mDataRced = 0;
                }
            }
            break;
        case LINK_RX_DATA: //接收数据
            mRxBuff[mBuffIndex++] = dat;
			mDataRced++;
            if (mDataRced == mPkgLen) //接收完毕
            {
                mEventBuff = LINK_EV_RECEIVED_PKG;  //标记一包接收完毕,稍后进行事件通知
                Link_mStatus = LINK_ST_IDLE;
                mRxStep = LINK_RX_HEAD_H;      //重新开始接收头H
                mBuffIndex = 0;
                mPortLocked = false;
            }
            break;
        default:
            mRxStep = LINK_RX_HEAD_H;
            mBuffIndex = 0;
            mPortLocked = false;
            break;
        }
    }
}

// 10ms执行一次
static void LinkLoop()
{
    // 超时判断与处理
    if(mRxStep > LINK_RX_HEAD_H) // 正在（等待）接收数据
    {
        mWaitTime++;
        if(mWaitTime == mTimeOut)   // 未收到数据超时
        {
            mPortLocked = false;
            mBuffIndex = 0;
            if(mRxStep == LINK_RX_IDENTIFY_DATA_LEN)
            {
                mRxStep = LINK_RX_HEAD_H;      //重新开始接收头H
                _Link_Event(LINK_EV_RECEIVED_PKG_TO);  // 没有后续数据的量产机
            }
            else    // 数据收到一半超时了
            {
                mRxStep = LINK_RX_HEAD_H;      //重新开始接收头H
                _Link_Event(LINK_EV_TIMEOUT);
            }
            Link_mStatus = LINK_ST_IDLE;
        }
    }
    else
    {
        mWaitTime = 0;
    }
    
    // 中断标记的事件通知处理
    if(mEventBuff)
    {
        _Link_Event(mEventBuff);
        mEventBuff = LINK_EV_NULL;
    }
#if (!_SYNC_WAIT)
    // VBUS延时处理
    if(mVBusTxDelayTime == 3)
    {
        _TW_SendDataVBus(mTxBuff,mTxBuffLen);   //VBUS已经输出高电平40ms了，开始发数据。
    }
    if(mVBusTxDelayTime < 10)mVBusTxDelayTime++;
#endif
}

void Link_Init()
{
    _TW_PortInit();
    Polsys_TaskInit(&mTimer, LinkLoop, 10/POLSYS_TICK_CYCLE);
}

bool Link_SendIdentify(u8 * buff, u8 len)
{
    mTxBuff = buff;
    mTxBuffLen = len;
    Link_mStatus = LINK_ST_WAIT_IDENTIFY;
    memset(mRxBuff, 0, sizeof(mRxBuff));    // 因为识别包可能没有长度信息，避免数据解析错误，清零。
    SendData();
    mWaitTime = 0;
    return true;
}

bool Link_Send(u8 * buff, u8 len)
{
    mTxBuff = buff;
    mTxBuffLen = len;
    Link_mStatus = LINK_ST_WAIT_DATA;
    SendData();
    mWaitTime = 0;
    return true;
}


IN_LINE u8* Link_GetPkg()
{
    return mRxBuff;
}

IN_LINE link_port_t Link_GetLastRecPort()
{
    return mLastRecPort;
}


IN_LINE void Link_SetPlugStatus(bool nst)
{
    mPlugIn = nst;
    if(!mPlugIn)mLastRecPort = LINK_PORT_UNKNOW;
}


// 内部函数


static void SendData()
{
    if(mPlugIn) // 有产品接入才发送数据
    {
        if(mLastRecPort == LINK_PORT_DP)
        {
            _TW_SendDataDp(mTxBuff, mTxBuffLen);
        }
        else if(mLastRecPort == LINK_PORT_VBUS)
        {
            VBusStartSend();
        }
        else
        {
            VBusStartSend();
            _TW_SendDataDp(mTxBuff, mTxBuffLen);
        }
    }
}

static void VBusStartSend()
{
    if(Link_mStatus == LINK_ST_WAIT_IDENTIFY)   // 识别包需要输出高40ms
    {
        _TW_SetVBusHigh();
#if (_SYNC_WAIT)
        Mcu_Delayms(40);
        _TW_SendDataVBus(mTxBuff, mTxBuffLen);
#else
        mVBusTxDelayTime = 0;
#endif
    }
    else    // 常规数据包直接发送。
    {
        _TW_SendDataVBus(mTxBuff, mTxBuffLen);
    }
}


